package com.fedoom.frontend.models;

import java.awt.*;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;

import javax.swing.*;

import com.fedoom.frontend.views.ModalView;

/**
 * 
 * @author tony
 *
 */
public class ArgCollection /*implements Serializable*/{
	
	private HashMap<String, String> hm = new HashMap<String, String>();
	private String filename = "./LauncherConfig.cfg";
	
	LinkedList<String> commandsList;	//added JM
	
	public ArgCollection() {
		
		//create CommandLineFile Loader to load file
		CommandLineFileLoader clfl = new CommandLineFileLoader("FeDoomCommands");
		commandsList = clfl.getCommands();	
	}
	

/**
 * Cycles through all components contained within JFrame
 * For JCheckBoxes, only names and empty strings will be added
 * If Checkbox is Unselected, it will be removed from hash
 * For JTextAreas, names & values will be added
 * if text ="", it will be removed from hash
 * 
 * No other components will be added to the collection
 * @param mv	The modal view whose data should be added.
 * @return	returns false when NO items were a 
 */
	public boolean addValues(ModalView mv)
	{
		int size =hm.size();
		addComponents(mv);
		
		if(hm.size()==size)
			return false;
		System.out.println("updateAC hm: " + hm);//
		return true;
	}
	
	/**
	 * Builds and executes command from stored Hashmap
	 * Logic:  
	 * -Iterates through the HashMap keys
	 * 		-takes each key and pulls associated command line from mapping file (stored in list)
	 * 		-Concatenates the value in the file with the User input Hashmap value
	 *	-Executes the concatenated value 
	 */
	public void launch(){
		
		int index;
		String command;				//corresponding value from the command line mapping file (preloaded list)
		String commandValue;		//corresponding value from the HashMap entry (UserInput)
		
		StringBuilder fullCommandLine = new StringBuilder();;
		
		for(Map.Entry<String, String> entry : hm.entrySet()) {
		    
			//key in HashMap was stored as a String,
			index = Integer.parseInt(entry.getKey());
			
			//Load command value from mapping file and user entered value
			command = commandsList.get(index);
			commandValue = entry.getValue();
			commandValue = commandValue.replaceAll("\"", "");	//strip quotes from values
			
			//Build string to execute
			fullCommandLine.append(command+" " + commandValue + " ");	
		}
		
		//show output for debugging
		System.out.println("Command line to execute: " + fullCommandLine);
		
		//execute full command line that was built
		Runtime run = Runtime.getRuntime();
		Process pr = null;
		StringBuffer output = new StringBuffer();
		
		try {
			pr = run.exec(fullCommandLine.toString());
			pr.waitFor();
		
			BufferedReader buf = new BufferedReader(new InputStreamReader(pr.getInputStream()));
			String line = "";
			
			while ((line = buf.readLine())!=null) {
				output.append(line);
				output.append("\n");
			}
			
		} catch (IOException e) {
			e.printStackTrace();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	

	/**
	 * Updates the UI with all of the values contained in hm
	 * @param infoView
	 * @return
	 */
	public boolean updateUI(JDialog infoView)
	{
//		return checkComponent (infoView);
		checkComponent (infoView);//
		System.out.println("updateui hm: " + hm);//
		return true;
	}
	
	/**
	 * Check if HashMap is empty
	 * @return true/false if Hashmap is empty (Boolean) 
	 */
	public boolean isEmpty()
	{
		return hm.isEmpty();
	}

	/**
	 * Checks if Component contains JCheckBox or JTextArea 
	 * @param parent - Parent Container
	 * @return - boolean
	 */
	private boolean checkComponent(Container parent) 
	{
		Container child;
		String key;
		for (int i=0;i <parent.getComponentCount();i++)
		{
			child=(Container)parent.getComponent(i);
			String classname=child.getClass().toString();
			key=child.getName();
			
			if (!hm.containsKey(key))
			{
				checkComponent(child);
			}
			else if(classname.equals("class javax.swing.JCheckBox"))
			{
				JCheckBox jbc = (JCheckBox)child;
				jbc.setSelected(true);
			}
			else if (classname.equals("class javax.swing.JTextArea"))
			{
				JTextArea jta = (JTextArea)child;
				jta.setText(hm.get(key));
			}
			else if (classname.equals("class javax.swing.JComboBox"))
			{
				JComboBox jcombo = (JComboBox)child;
				jcombo.setSelectedIndex(Integer.parseInt(hm.get(key)));
			}
			else
			{
				checkComponent(child);
			}
			
		}
		return false;
	}

	/**
	 * Adds Component values to HashMap<String,String> hm (key,value)
	 * @param parent - Container to add
	 */
	private void addComponents(Container parent) {
		Container child;
		String key,value;
		for(int i = 0;i<parent.getComponentCount();i++)
		{
			child=(Container)parent.getComponent(i);
			String classname=child.getClass().toString();
			key=child.getName();
						
			if(classname.equals("class javax.swing.JCheckBox"))
			{
				JCheckBox jbc = (JCheckBox)child;
				if (jbc.isSelected()==true)
				{
					value="";
					hm.put(key, value);	
				}
				else
				{
					hm.remove(key);
				}
			}
			else if (classname.equals("class javax.swing.JTextArea"))
			{
				JTextArea jta = (JTextArea)child;
				value=jta.getText();
				if(value.equals(""))
				{
					hm.remove(key);
				}
				else
				{
					hm.put(key, value);
				}
			}
			else if (classname.equals("class javax.swing.JComboBox"))
			{
				JComboBox jcombo = (JComboBox)child;
				value=String.valueOf(jcombo.getSelectedIndex());
				if(value.equals("0"))
				{
					hm.remove(key);
				}
				else
				{
					hm.put(key, value);
				}
			}
			else
			{
				addComponents(child);
			}
		}
	}

	/**
	 * Writes serializable Hashmap hm to object file
	 */
	public void writeConfig() {	
		
		try {
			FileOutputStream fs = new FileOutputStream(this.filename);
			ObjectOutputStream os = new ObjectOutputStream(fs);
			os.writeObject(this.hm);
			os.close();
			fs.close();
		} catch (IOException ex) {
			ex.printStackTrace();
		} catch (Exception ex2) {
			ex2.printStackTrace();
		}
	}
	
	/**
	 * Reads Config file from previous object into the HashMap hm
	 * @return HashMap of previous values (HashMap)
	 */
	@SuppressWarnings("unchecked")
	public HashMap<String, String> readConfig() {
		
		/*  - Commented out by Justin so I can proceed - 
		 * 	  the code was giving duplicate entries whenever i closed the app and reloaded 
		 *    then selected new values.
		 *    
		try {
			FileInputStream fs = new FileInputStream(this.filename);
			ObjectInputStream os = new ObjectInputStream(fs);
			hm = (HashMap<String, String>) os.readObject();
			os.close();
			fs.close();
		} catch (IOException ex) {
			ex.printStackTrace();
		} catch (ClassNotFoundException cx) {
			cx.printStackTrace();
		} finally {
			
		}
		*/
		return hm;
		
		
	}
	
	/**
	 * Check if Config File already exists
	 * @return true/false if file exists (Boolean)
	 */
	public boolean isConfigFileExist () {
		boolean blnExists = false;
		
		File file = new File(this.filename);
		blnExists = file.exists();
		
		return blnExists;
	}
	
	/**
	 * Get file name of config file
	 * @return filename (String)
	 */
	public String getFilename() {
		return filename;
	}

	/**
	 * Sets filename for config file
	 * @param filename
	 */
	public void setFilename(String filename) {
		this.filename = filename;
	}
}
